import pandas as pd
from utils.common import *
from feature_set.base_feature import BaseFeature, RequstData
from feature_set.loan.un.loan_un_base_v2.loan_un_onloan_v2 import LoanUnOnloanV2
from feature_set.loan.un.loan_un_base_v2.loan_un_extension_v2 import LoanUnExtensionV2
from feature_set.loan.un.loan_un_base_v2.loan_un_fake_v2 import LoanUnfakeV2


class LoanUnBaseV2(BaseFeature):
    def __init__(self):
        super().__init__()
        self.country_abbr = None
        self.acq_channel = None
        self.app_order_id = None
        self.apply_time = None
        self.product_info = None
        self.product_code = None
        self.current_amount = None
        self.current_days_per_term = None
        self.current_term = None
        self.order_apply_time = None
        self.order_apply_time_datetime = None
        self.order_apply_date = None
        self.order_data_df = None
        self.installments_data_df = None
        self.contract_data_df = None
        self.function_map = {
            'gen_onloan_feature': self.gen_onloan_feature,
            'gen_extension_feature': self.gen_extension_feature,
            'gen_fake_feature': self.gen_fake_feature
        }

    def load_conf(self):
        """
        load config file
        Returns:

        """
        pass

    def load_request(self, request_data: RequstData):
        """
        get request data and format feature input data
        Args:
            request_data: input detail data

        Returns:
            format order_data_a installments_data_a contract_data_a
        """
        self.country_abbr = request_data.country_abbr.lower()
        self.acq_channel = request_data.acq_channel.lower()
        self.app_order_id = request_data.order_id
        self.apply_time = request_data.apply_time
        if self.app_order_id != 'null':
            self.product_info = request_data.data_sources.get('user_info_1', {}).get('productInfo', {})
            self.product_code = self.product_info['productCode'].lower() if self.product_info['productCode'] else ''
            self.current_amount = int(self.product_info['amount']) if self.product_info['amount'] else 0
            self.current_days_per_term = int(self.product_info['daysPerTerm']) if self.product_info['daysPerTerm'] else 0
            self.current_term = int(self.product_info['term']) if self.product_info['term'] else 0
            self.order_apply_time = self.product_info['createTime']
        else:
            self.product_code = ''
            self.current_amount = 0
            self.current_days_per_term = 0
            self.current_term = 0
            self.order_apply_time = self.apply_time
        self.order_apply_time_datetime = datetime.strptime(self.order_apply_time, "%Y-%m-%d %H:%M:%S")
        self.order_apply_date = self.order_apply_time[:10]
        order_data_a = request_data.data_sources.get('order_data_a', [])
        installments_data_a = request_data.data_sources.get('installments_data_a', [])
        contract_data_a = request_data.data_sources.get('contract_data_a', [])

        if order_data_a:
            self.order_data_df = pd.DataFrame(order_data_a)
        else:
            self.order_data_df = pd.DataFrame(columns=['id',
                                                       'app_order_id',
                                                       'user_id',
                                                       'acq_channel',
                                                       'device_type',
                                                       'product_name',
                                                       'product_code',
                                                       'product_set_code',
                                                       'loan_amount',
                                                       'down_payment',
                                                       'user_name',
                                                       'id_card_number',
                                                       'phone_number',
                                                       'apply_time',
                                                       'personal_info',
                                                       'work_info',
                                                       'contact_info',
                                                       'bank_account_info',
                                                       'ktp_info',
                                                       'face_recognition_info',
                                                       'product_info',
                                                       'app_track_id',
                                                       'status',
                                                       'rejected_until',
                                                       'new_old_user_status',
                                                       'create_time',
                                                       'update_time',
                                                       'submit_type'])
            self.logger.info('输入数据order_data_a结点为空')

        if installments_data_a:
            self.installments_data_df = pd.DataFrame(installments_data_a)
        else:
            self.installments_data_df = pd.DataFrame(columns=['id',
                                                              'user_id',
                                                              'acq_channel',
                                                              'app_order_id',
                                                              'contract_no',
                                                              'repayment_date',
                                                              'installment_num',
                                                              'installment_amount',
                                                              'principal',
                                                              'interest',
                                                              'cut_interest',
                                                              'service_fee',
                                                              'management_fee',
                                                              'overdue_interest',
                                                              'overdue_days',
                                                              'penalty',
                                                              'extension_fee',
                                                              'repaid_principal',
                                                              'repaid_interest',
                                                              'repaid_cut_interest',
                                                              'repaid_service_fee',
                                                              'repaid_management_fee',
                                                              'repaid_overdue_interest',
                                                              'repaid_penalty',
                                                              'discount_amount',
                                                              'waive_amount',
                                                              'settlement_type',
                                                              'extension_count',
                                                              'new_old_user_status',
                                                              'status',
                                                              'create_time',
                                                              'update_time'])
            self.logger.info('输入数据installments_data_a结点为空')

        if contract_data_a:
            self.contract_data_df = pd.DataFrame(contract_data_a)
        else:
            self.contract_data_df = pd.DataFrame(columns=['id',
                                                          'user_id',
                                                          'acq_channel',
                                                          'app_order_id',
                                                          'contract_no',
                                                          'phone_number',
                                                          'email',
                                                          'name',
                                                          'id_card_number',
                                                          'gender',
                                                          'product_set_code',
                                                          'product_code',
                                                          'product_name',
                                                          'term',
                                                          'days_per_term',
                                                          'down_payment',
                                                          'total_repay_amount',
                                                          'total_repaid_amount',
                                                          'loan_amount',
                                                          'receipt_amount',
                                                          'service_fee',
                                                          'interest',
                                                          'cut_interest',
                                                          'management_fee',
                                                          'overdue_interest',
                                                          'penalty',
                                                          'bank_account_id',
                                                          'bank_account_type',
                                                          'bank_account_no',
                                                          'bank_id',
                                                          'bank_name',
                                                          'cash_deposit',
                                                          'settlement_time',
                                                          'activation_time',
                                                          'status',
                                                          'fail_reason',
                                                          'label',
                                                          'create_time',
                                                          'update_time'])
            self.logger.info('输入数据contract_data_a结点为空')
        self.process_data()

    def process_data(self):
        self.order_data_df = self.order_data_df[self.order_data_df['status'].isin([21, 22])]

        self.installments_data_df = pd.merge(self.installments_data_df, self.order_data_df[['app_order_id', 'apply_time', 'product_code']].drop_duplicates(subset=['app_order_id']), on=['app_order_id'])
        self.installments_data_df = self.installments_data_df[self.installments_data_df['status'].isin([1, 2])]
        self.installments_data_df['acq_channel'] = self.installments_data_df['acq_channel'].str.lower()
        self.installments_data_df['product_code'] = self.installments_data_df['product_code'].str.lower()
        self.installments_data_df['amount'] = self.installments_data_df['principal'] + self.installments_data_df['interest']
        self.installments_data_df['day_interval'] = (pd.to_datetime(self.order_apply_time, format="%Y-%m-%d %H:%M:%S") - pd.to_datetime(self.installments_data_df['create_time'], format="%Y-%m-%d %H:%M:%S")).dt.total_seconds() / (60 * 60 * 24)
        self.installments_data_df['create_time_hour'] = self.installments_data_df['create_time'].str.slice(11, 13).astype(int)
        if not self.installments_data_df.empty:
            self.installments_data_df['is_workday'] = self.installments_data_df.apply(lambda x: get_workday(x['create_time']), axis=1)
            self.installments_data_df['is_holiday'] = self.installments_data_df.apply(lambda x: get_holidays(self.country_abbr, x['create_time']), axis=1)
        else:
            self.installments_data_df['is_workday'] = float('nan')
            self.installments_data_df['is_holiday'] = float('nan')

        self.contract_data_df = self.contract_data_df[self.contract_data_df['status'].isin([4, 6])]
        self.contract_data_df['settlement_date'] = self.contract_data_df['settlement_time'].str.slice(0, 10)  # 还款时间
        self.contract_data_df['activation_date'] = self.contract_data_df['activation_time'].str.slice(0, 10)  # 放款时间
        self.contract_data_df['amount'] = self.contract_data_df['loan_amount'] + self.contract_data_df['interest']
        # 回溯历史数据
        self.order_data_df = self.order_data_df[self.order_data_df['apply_time'] <= self.order_apply_time]
        self.installments_data_df = self.installments_data_df[self.installments_data_df['create_time'] <= self.order_apply_time]
        self.installments_data_df = self.installments_data_df.apply(self.get_installments_data, args=(self.order_apply_time,), axis=1)
        self.contract_data_df = self.contract_data_df[self.contract_data_df['activation_time'] <= self.order_apply_time]
        self.contract_data_df = self.contract_data_df.apply(self.get_contract_data, args=(self.order_apply_time,), axis=1)

    def get_days_inter(self, end_time, start_time):
        end_time = datetime.strptime(end_time, "%Y-%m-%d %H:%M:%S")
        start_time = datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S")
        interval = end_time - start_time
        return int(interval.days)

    def get_installments_data(self, df, current_apply_time):
        # 对于未还清的订单,判断是逾期在贷还是未到还款日当前在贷
        if df['status'] == 1:
            if current_apply_time[:10] > df['repayment_date']:
                overdue_days = self.get_days_inter(current_apply_time, df['repayment_date'] + ' 00:00:00')
            else:
                overdue_days = 0
        # 对于已经还清的账单，计算还清时间与回溯时间的差距 重新计算逻辑
        if df['status'] == 2:
            if current_apply_time >= df['update_time']:  # 对于还清的账单判断还清类型
                overdue_days = self.get_days_inter(df['update_time'], df['repayment_date'] + ' 00:00:00')
            elif current_apply_time < df['update_time']:  # 还清时间在当前申请时间之后的
                df['status'] = 1
                if current_apply_time[:10] > df['repayment_date']:
                    overdue_days = self.get_days_inter(current_apply_time, df['repayment_date'] + ' 00:00:00')
                else:
                    overdue_days = 0
        df['overdue_days'] = overdue_days
        return df

    def get_contract_data(self, df, current_apply_time):
        if df['status'] == 6 and current_apply_time < df['settlement_time']:
            df['status'] = 4
            df['settlement_time'] = None
            df['total_repaid_amount'] = 0
        return df

    def gen_onloan_feature(self):
        onloan_v2 = LoanUnOnloanV2(self)
        return onloan_v2.gen_features()

    def gen_extension_feature(self):
        extloan_v2 = LoanUnExtensionV2(self)
        return extloan_v2.gen_features()

    def gen_fake_feature(self):
        fakeloan_v2 = LoanUnfakeV2(self)
        return fakeloan_v2.gen_features()
